// import {cloneDeep} from 'lodash'

// 相关 pipeline 工具

import { Edge, Node } from '@/components/studio/data/interface'
/**
 * 获取 有父 节点 task
 * @param chooseTasks
 */
export function getTaskHaveParent(chooseTasks: any) {
  const haveParentTasks = chooseTasks.filter((item: any) => {
    return typeof item.parentId === 'string'
  })
  return haveParentTasks
}

/**
 * 获取 有父 节点 task
 * @param chooseTasks
 */
export function getTaskHaveChild(chooseTasks: any) {
  const haveChildTasks = chooseTasks.filter((item: any) => {
    return typeof item.childId === 'string'
  })
  return haveChildTasks
}

/**
 * 根据 ids 获取 画布中 所有节点, （可过滤掉指定多个的 id）
 * @param allNode eg:array 画布所有节点
 * @param ids eg:'1,2,3'
 * @param filterIds eg:[1,2,3]  过滤的id
 */
export function getAllTaskByIds(
  allNode: any,
  ids: string,
  filterIds: Array<number>
) {
  if (ids) {
    const idsArray = new Set(ids.split(',').map((id: string) => Number(id)))
    return allNode.filter(
      (item: any) => idsArray.has(item.id) && !filterIds.includes(item.id)
    )
  }
  return []
}

// 查找到的当前节点 [getNodeById, getNodeByPosition, ]
let currentTask: any = null
/**
 * 获取指定 id 的 节点 task
 * @param allNode  pipeline 所有节点
 * @param id
 */
export function getNodeById(allNode: any, id: number) {
  currentTask = allNode.filter((item: any) => item.id === id)
  // 返回第一个
  if (currentTask.length > 0) {
    return currentTask[0]
  }
  return null
}

/**
 * 获取指定行列的 节点 task
 * @param allNode  pipeline 所有节点
 * @param col
 * @param row
 */
export function getNodeByPosition(allNode: any, col: number, row: number) {
  currentTask = allNode.filter(
    (item: any) =>
      item.data.position.col === col && item.data.position.row === row
  )
  // 返回第一个
  if (currentTask.length > 0) {
    return currentTask[0]
  }
  return null
}

/**
 * 获取框选节点 父节点 col 位置最大值  和 子节点位置 col 最小值 （在发货区父子节点时需要过滤掉所选择的节点 ）
 * 列 左右限制
 * @param allNode
 * @param chooseTasks
 */
export function getParentSonPosition(allNode: any, chooseTasks: any) {
  // 拖拽 所有节点的 id
  const chooseIds = chooseTasks.map((item: any) => {
    return item.id
  })

  let colParentMax: number | null = null
  let colChildMin: number | null = null
  // 父节点最大值数组
  const colParentMaxArray: number[] = []
  // 子节点最大值数组
  const colChildMinArray: number[] = []

  // todo 框选多节点 拖拽 问题
  // 所以节点的父节点最大值， 所有节点子节点最大值 (过滤选择的到的节点)
  chooseTasks.forEach((task: any) => {
    // 父节点计算  最大定位
    if (task.parentId) {
      const parentTaskArray = getAllTaskByIds(allNode, task.parentId, chooseIds)
      // parentTaskArray 有节点 就限制 没有就不限制
      if (parentTaskArray.length > 0) {
        colParentMaxArray.push(
          Math.max(
            ...parentTaskArray.map((item: any) => {
              return item.data.position.col
            })
          )
        )
      } else {
        colParentMaxArray.push(0)
      }
    }
    // 子节点计算 最大定位
    if (task.childId) {
      const childTaskArray = getAllTaskByIds(allNode, task.childId, chooseIds)
      if (childTaskArray.length > 0) {
        colChildMinArray.push(
          Math.min(
            ...childTaskArray.map((item: any) => {
              return item.data.position.col
            })
          )
        )
      } else {
        // 有可能  多个
        colChildMinArray.push(1000)
      }
    }
  })
  //  为空的 是没有 父节点
  colParentMax =
    colParentMaxArray.length > 0 ? Math.max(...colParentMaxArray) : null
  colChildMin =
    colChildMinArray.length > 0 ? Math.min(...colChildMinArray) : null
  // 框选节点的最小 最大 列
  const allChooseTaskCol = chooseTasks.map((item: any) => {
    return item.data.position.col
  })
  const chooseTaskMinCol = Math.min(...allChooseTaskCol)
  const chooseTaskMaxCol = Math.max(...allChooseTaskCol)

  if (colParentMax && colParentMax >= chooseTaskMinCol) {
    colParentMax = chooseTaskMinCol - 1
  }
  if (colChildMin && colChildMin <= chooseTaskMaxCol) {
    colChildMin = chooseTaskMaxCol + 1
  }
  return { colParentMax, colChildMin }
}

// 下一列所有节点
let nextColNodes: any = null
let nextColNodesRow: any = null

/**
 * 添加算子  计算节点后的 空位, 邻近行
 */
export function ComputeSpaceAfterNode(allNode: Array<any>, addInfo: any) {
  let targetRow = 0
  const { col, row } = addInfo.nodePosition
  // 下一列所有节点
  nextColNodes = allNode.filter((item) => {
    return item.data.position.col === col + 1
  })
  // 下一列 所有节点的行
  nextColNodesRow = new Set(
    nextColNodes.map((item: any) => item.data.position.row)
  )
  // 如果这个
  for (let i = 0; i < 20; i += 1) {
    if (!nextColNodesRow.has(row - i) && row - i > 0) {
      targetRow = row - i
      break
    } else if (!nextColNodesRow.has(row + i)) {
      targetRow = row + i
      break
    }
  }
  return { addCol: col + 1, addRow: targetRow }
}

/**
 * 从 所有节点中过滤掉 指定 多个id 的节点
 */
export function filtersNodesSpecifyIds(
  allNode: Array<any>,
  chooseNodes: Array<any>
) {
  const idsArray = new Set(chooseNodes.map((item: any) => item.id))
  return allNode.filter((item: any) => !idsArray.has(item.id))
}

// 拖拽重叠检测 初始位置， 与拖拽位置差值 [ nodeOverlapDetection ]
let processRowDifferences: number = 0
let processColDifferences: number = 0
// 除框选外的其他节点 [ nodeOverlapDetection ]
let nodesOtherThanChoose: any = null
/**
 * 框选 节点 拖拽 重叠 检测
 * @param targetPosition  目标位置
 * @param startPosition  初始位置
 * @param allNode
 * @param chooseNodes
 */
export function nodeOverlapDetection(
  targetPosition: any,
  startPosition: any,
  allNode: Array<any>,
  chooseNodes: Array<any>
) {
  processRowDifferences = targetPosition.row - startPosition.row
  processColDifferences = targetPosition.col - startPosition.col
  const statusArray: any[] = []
  // 除框选外的其他节点
  nodesOtherThanChoose = filtersNodesSpecifyIds(allNode, chooseNodes)
  chooseNodes.forEach((item: any) => {
    const haveNode = getNodeByPosition(
      nodesOtherThanChoose,
      item.data.position.col + processColDifferences,
      item.data.position.row + processRowDifferences
    )
    // 没有跳出 foreach
    if (haveNode) {
      statusArray.push(0)
    } else {
      statusArray.push(1)
    }
  })
  return !statusArray.includes(0)
}

// 生成节点对 [ recursionDealLine ]
let nodeLinePair: any = []
/**
 * 生成节点对
 * @param allNode
 * @param nodeId
 * @param type
 * @param result
 * @constructor
 */

export function recursionDealLine(
  allNode: Array<any>,
  nodeId: number,
  type: string,
  result: any[]
) {
  // 节点对
  nodeLinePair = result
  // 内部函数
  function DealLinePair(nodeId2: number) {
    // 找到节点
    const [currentPairTask] = allNode.filter((item: any) => item.id === nodeId2)
    // 遍历父子节点
    if (
      currentPairTask &&
      typeof currentPairTask[type] === 'string' &&
      currentPairTask[type].length > 0
    ) {
      currentPairTask[type].split(',').forEach((id: string) => {
        nodeLinePair.push(
          type === 'parentId' ? `${id}-${nodeId2}` : `${nodeId2}-${id}`
        )
        DealLinePair(Number(id))
      })
    }
  }
  DealLinePair(nodeId)
  return nodeLinePair
}

/**
 * 计算 最大值 最小值的差值
 */
export function outputMaxPrice(numberList: number[]) {
  const min = Math.min(...numberList)
  const max = Math.max(...numberList)
  return max - min
}

// 复制的几点占有列宽   [ComputeSpaceByNodes]
let colDemandSize: number = 0
/**
 * 复制算子  获取空位 （从第一列查找）
 * @param allNode
 * @param copyNodes
 * @param type true 根据索要复制的节点数量定位， false 根据所有节点最大 row 定位
 */
export function ComputeSpaceByNodes(
  allNode: Array<any>,
  copyNodes: Array<any>,
  type: boolean
) {
  let maxRow: number
  if (type) {
    // 复制的几点占有列宽
    colDemandSize =
      outputMaxPrice(copyNodes.map((node: any) => node.data.position.col)) + 1
    // 计算 前 colDemandSize 列的最大值 (根据所复制的节点数量定位 maxiRowForFirstNCol)
    const nodesForFirstNCol = allNode.filter(
      (node: any) => node.data.position.col <= colDemandSize
    )
    maxRow =
      Math.max(
        ...nodesForFirstNCol.map((node: any) => node.data.position.row)
      ) + 1
  } else {
    // 根据所有节点 最大行定位
    maxRow = Math.max(...allNode.map((node: any) => node.data.position.row)) + 1
  }
  return { col: 1, row: maxRow }
}

/**
 * 获取所有有 parentId 的节点， 生成节点对
 * parentId: string '23,45,56' 多个父节点 ',' 隔开
 * 父节点Id        子节点Id
 * [{nodeId: id}, { nodeId: id}]
 */
export function edgesList(allNode: Array<Node>) {
  const edges: Array<any> = []
  if (allNode?.length > 0) {
    allNode.forEach((node: any) => {
      // 存在parentId
      if (node.parentId) {
        const parentIdArray = node.parentId.split(',')
        if (parentIdArray.length > 0) {
          // 多个父节点  生成多个父子关系
          parentIdArray.forEach((parentId: string) => {
            edges.push([{ nodeId: Number(parentId) }, { nodeId: node.id }])
          })
        }
      }
    })
  }
  return edges
}

/**
 * 根据 列 位置计算 节点 x 位置
 * 节点 css 等
 * @param col 列
 * @param gridSizeWidth
 * @param differenceOfGridWidth
 */
export function calcXPositionByCol(
  col: number,
  gridSizeWidth: number,
  differenceOfGridWidth: number
) {
  return (col - 1) * gridSizeWidth + differenceOfGridWidth
}

/**
 * 根据 行 位置计算 节点 y 位置
 * 节点 css 等
 * @param row 行
 * @param gridSizeHeight
 * @param differenceOfGridHeight
 */
export function calcYPositionByRow(
  row: number,
  gridSizeHeight: number,
  differenceOfGridHeight: number
) {
  return (row - 1) * gridSizeHeight + differenceOfGridHeight
}

/**
 * 生成连接线对象
 */
export function generateEdgeInfo(allNode: Array<Node>, nodeInfo: any) {
  const {
    nodeHeight,
    nodeWidth,
    gridSizeWidth,
    gridSizeHeight,
    differenceOfGridWidth,
    differenceOfGridHeight,
  } = nodeInfo
  const edgeInfo: Array<Edge> = []
  const edges = edgesList(allNode)
  // 遍历节点对
  edges.forEach((nodePair: any) => {
    const startElement: any = getNodeById(allNode, nodePair[0].nodeId)
    const endElement: any = getNodeById(allNode, nodePair[1].nodeId)
    if (
      startElement &&
      Object.keys(startElement).length > 0 &&
      Object.keys(endElement).length > 0
    ) {
      // 父子节点 y 方向的相对关系， true 父节点 在下方
      const chileGreaterParentOfY: boolean =
        startElement.data.position.row > endElement.data.position.row
      // 起始点（父节点）
      const startCenter = {
        x:
          calcXPositionByCol(
            startElement.data.position.col,
            gridSizeWidth,
            differenceOfGridWidth
          ) + nodeWidth,
        y: chileGreaterParentOfY
          ? calcYPositionByRow(
              startElement.data.position.row,
              gridSizeHeight,
              differenceOfGridHeight
            ) + nodeHeight
          : calcYPositionByRow(
              startElement.data.position.row,
              gridSizeHeight,
              differenceOfGridHeight
            ),
      }
      // 结束点 （子节点）
      const endCenter = {
        x: calcXPositionByCol(
          endElement.data.position.col,
          gridSizeWidth,
          differenceOfGridWidth
        ),
        y: chileGreaterParentOfY
          ? calcYPositionByRow(
              endElement.data.position.row,
              gridSizeHeight,
              differenceOfGridHeight
            )
          : calcYPositionByRow(
              endElement.data.position.row,
              gridSizeHeight,
              differenceOfGridHeight
            ) + nodeHeight,
      }
      // 连接线在画布中的相对位置， 由于 子节点始终在父节点右侧的限制， x 方向的位置始终为父节点 x 位置
      const x = Math.min(startCenter.x, endCenter.x)
      const y = Math.min(startCenter.y, endCenter.y)
      // 所有连接线信息
      edgeInfo.push({
        startNodeId: startElement.id, // 开始节点id
        endNodeId: endElement.id, // 结束节点id
        startEndPos: {
          // 相对 svg
          xStart: startCenter.x - x, //
          yStart: startCenter.y - y, // 起始点位置
          xEnd: endCenter.x - x, // x方向的差值
          yEnd: endCenter.y - y, //  结束点位置
          yStatus: chileGreaterParentOfY,
          rowEqual:
            startElement.data.position.row === endElement.data.position.row,
        },
        x,
        y,
      })
    }
  })
  return edgeInfo
}

/**
 * 根据要拖拽的节点 位置 计算 示意网格尺寸
 * @param selectNodes 要拖拽的节点
 */
export function calcNodeGridSize(selectNodes: any) {
  if (selectNodes.length > 0) {
    const colMin = Math.min(
      ...selectNodes.map((item: any) => {
        return item.data.position.col
      })
    )
    const rowMin = Math.min(
      ...selectNodes.map((item: any) => {
        return item.data.position.row
      })
    )
    const colMax = Math.max(
      ...selectNodes.map((item: any) => {
        return item.data.position.col
      })
    )
    const rowMax = Math.max(
      ...selectNodes.map((item: any) => {
        return item.data.position.row
      })
    )
    // 拖拽示意框 尺寸 行列
    return { rowCount: rowMax - rowMin + 1, colCount: colMax - colMin + 1 }
  }
  return { rowCount: 0, colCount: 0 }
}

/**
 * 目标节点是否可以接受此节点为输入，
 * 数据节点不接受， 有足够数量的父节点的节点不接受
 */
export function acceptNodeInputOrNot(connectedNode: any): boolean {
  let accept: boolean = false
  // 不是数据节点
  if (connectedNode && connectedNode.type !== 3) {
    // （没有最大父节点连接数）|| ( 有连接数， 且父节点数量小于该连接数 || 没有父节点)
    if (
      !connectedNode.data.maxParentNumber ||
      connectedNode.data.maxParentNumber === -1 ||
      (connectedNode.data.maxParentNumber &&
        (connectedNode.data.maxParentNumber >
          connectedNode.parentId.split(',').length ||
          !connectedNode.parentId))
    ) {
      accept = true
    }
  }
  return accept
}

/**
 * 目标节点是否可以接受此节点为输入，
 * 数据节点不接受， 有足够数量的父节点的节点不接受
 * @param position 拖拽移动的位置
 * @param ranksOfLimit 根据父子节点关系计算的左右列限制
 * @param nodeGridSize 尺寸， 选择的节点尺寸，
 * @param gridStartDragPosition 拖拽初始位置， 多个节点组成的大的
 * @param allNode 所有节点
 * @param draggingNodeItem 拖拽的节点
 */
export function calcGridShow(
  position: any,
  ranksOfLimit: any,
  nodeGridSize: any,
  gridStartDragPosition: any,
  allNode: Array<any>,
  draggingNodeItem: any
): boolean {
  const { col, row } = position
  const { colParentMax, colChildMin } = ranksOfLimit
  // 判断多节点拖拽 超出列范围
  const { colCount } = nodeGridSize
  // 计算 覆盖状态 true 没有覆盖
  const coveredStatus = nodeOverlapDetection(
    { col, row },
    gridStartDragPosition,
    allNode,
    draggingNodeItem
  )
  // todo 上下方向， 拖拽到 其他节点上时候
  // 计算 父节点 最大 位置， 子节点 最小位置  typeof 由于 0 列限制
  //  父子 节点 判断是否显示
  if (
    (typeof colParentMax === 'number' && col <= colParentMax) ||
    (colChildMin && col + colCount - 1 >= colChildMin)
  ) {
    return false
  }
  // false 覆盖, 并且是在拖拽过程中
  return coveredStatus
}

// 屏幕快照
export function saveCanvasToImage(
  context: CanvasRenderingContext2D,
  startX: number,
  startY: number,
  width: number,
  height: number
) {
  // 获取裁剪框区域图片信息
  const img = context.getImageData(startX, startY, width, height)
  // 创建canvas标签，用于存放裁剪区域的图片
  const canvas = document.createElement('canvas')
  canvas.width = width
  canvas.height = height
  // 获取裁剪框区域画布
  const imgContext = canvas.getContext('2d')
  if (imgContext) {
    // 将图片放进裁剪框内
    imgContext.putImageData(img, 0, 0)
    const a = document.createElement('a')
    // 获取图片
    a.href = canvas.toDataURL('png')
    // 下载图片
    a.download = `${new Date().getTime()}.png`
    a.click()
  }
}

// 网格是否可放置节点计算
export function gridAvaliable(edgeInfo: any[], info: any) {
  // { 子节点id : [不可放置点] }
  // console.log(edgeInfo)
  const { nodeWidth, nodeHeight, gridSizeWidth, gridSizeHeight } = info
  const girdMap: any = {}
  edgeInfo.forEach((item) => {
    const rowStart = item.startEndPos.yStatus
      ? (item.y + item.startEndPos.yStart + (gridSizeHeight - nodeHeight) / 2) /
        gridSizeHeight
      : (item.y - (gridSizeHeight - nodeHeight) / 2) / gridSizeHeight + 1
    const columnStart =
      (item.x - (gridSizeWidth - (gridSizeWidth - nodeWidth) / 2)) /
        gridSizeWidth +
      1

    // const rowEnd = item.startEndPos.yStatus?((rowStart-(item.startEndPos.yStart-40)/gridSizeHeight)):((item.startEndPos.yEnd-40)/gridSizeHeight+rowStart)
    const columnEnd =
      (item.x + item.startEndPos.xEnd - (gridSizeWidth - nodeWidth) / 2) /
        gridSizeWidth +
      1

    // console.log(rowStart,columnStart)
    // console.log(rowEnd,columnEnd)

    // obj = {nodeId: String, grids: any[]}
    // const length = Math.max(columnStart,columnEnd)
    const length = Math.abs(columnStart - columnEnd) - 1
    const space = new Array(length).keys()
    const keys: any[] = [...space]

    keys.forEach((index) => {
      // if(index===length-1){
      //   keys[index] = `${rowEnd}-${columnStart+index}`
      // }else{
      //   keys[index] = `${rowStart}-${columnStart+index}`
      // }
      keys[index] = `${rowStart}-${columnStart + index + 1}`
    })
    // girdArray = girdArray.concat(keys)
    // console.log(keys)
    if (girdMap[item.endNodeId]) {
      const array = girdMap[item.endNodeId]
      girdMap[item.endNodeId] = array.concat(keys)
    } else {
      girdMap[item.endNodeId] = keys
    }
  })
  // console.log(girdMap)
  return girdMap
}
